/*
 * Copyright (C) 2010  Felip Moll
 * Copyright (C) 2010  Robert Millan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/* A simple server in the internet domain using TCP
   The port number is passed as an argument */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <error.h>

int
main (int argc, char *argv[])
{
  int socket_fd, new_socket_fd, port_num, cli_len;

  char buffer[256];

  struct sockaddr_in serv_addr, cli_addr;

  int n;

  if (argc < 2)
    {
      fprintf (stderr, "(Example.Server): No port provided\n");
      fprintf (stderr, "Usage: ./server <port>\n");
      exit (1);
    }

  //Obrim un nou socket de tipus INET i STREAM
  socket_fd = socket (AF_INET, SOCK_STREAM, 0);
  
  //Si no em pogut obrir cap socket
  if (socket_fd < 0) error (1, errno, "(Example.Server): Error opening socket");

  //Posem els sizeof(serv_addr) primers bytes de serv_addr a '\0' (és a dir, netejem l'struct)
  bzero ((char *) &serv_addr, sizeof (serv_addr));

  //Obtenim el num de port de l'argument
  port_num = atoi (argv[1]);

  //Omplim l'struct
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = 0x101A8C0;//INADDR_ANY means 0.0.0.0 (all ifaces),  0x200000A Means 10.0.0.2

  /*Amb HTONS convertim el nombre de port de host to network (la s és de unsigned Short int)
    On the i386 the host byte order is Least Significant Byte first, whereas the network byte order, as used on the Internet, is Most Significant Byte first.
  */
  serv_addr.sin_port = htons (port_num);

  printf("(Example.Server): Going to bind()\n");
  //bind: assigning a name to a socket. Li dona una @ física, ja que socket_fd està al namespace però no té @ assignada.
  if (bind (socket_fd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) error (1, errno, "(Example.Server): Error on binding()");
  
  
  //Converteix el socket a TCP PASSIVE SOCKET. El 5 vol dir suportar màx. 5 connexions simultànes. Si se li intenten connectar
  //llança un EECONNREFUSED
  printf("(Example.Server): Going to listen()\n");
  if (listen (socket_fd, 1) < 0) 
    {
      printf("(Example.Server): :Listen not succsessful\n");
      exit(0);
    }

  while (1) {
  //Creem un nou socket per el que rebem
  cli_len = sizeof (cli_addr);

  //Amb accept rebrem les dades de la connexió de socket_fd
  printf("(Example.Server): Going to accept()\n"); 
 
  new_socket_fd = accept (socket_fd, (struct sockaddr *) &cli_addr, &cli_len);

  if (new_socket_fd < 0) error (1, errno, "(Example.Server): Error on accept()");

  //Si rebem dades, netejem buffer i llegim del socket
  bzero (buffer, 256);
  printf("(Example.Server): Going to read\n");
  n = read (new_socket_fd, buffer, 255);
  
  if (n < 0) error (1, errno, "(Example.Server): Error reading from socket");
  
  printf ("(Cli->Srv): Here is the message: %s\n", buffer);
  printf("(Example.Server): Going to write\n");
  n = write (new_socket_fd, "(Srv->Cli): I received your message", 35);
  
  if (n < 0) error (1, errno, "(Example.Server): Error writing to socket");
  }

  return 0;
}
